/* 
 * File:   main.c
 * Author: Twistx77
 *
 * Created on 21 de junio de 2012, 7:17
 */



#pragma config WDTEN = OFF          //WDT disabled (enabled by SWDTEN bit)
#pragma config PLLDIV = 2           //Divide by 2 (8 MHz oscillator input)
#pragma config STVREN = ON            //stack overflow/underflow reset enabled
#pragma config XINST = OFF         //Extended instruction set disabled
#pragma config CPUDIV = OSC2_PLL2          //Divided by 2 to provide 24Mhz Clock
#pragma config CP0 = OFF            //Program memory is not code-protected
#pragma config OSC = INTOSCPLL     //Internal Oscillator with PLL optional
#pragma config T1DIG = OFF          //Sec Osc clock source may not be selected, unless T1OSCEN = 1
#pragma config LPT1OSC = OFF        //high power Timer1 mode
#pragma config FCMEN = OFF          //Fail-Safe Clock Monitor disabled
#pragma config IESO = OFF           //Two-Speed Start-up disabled
#pragma config WDTPS = 32768        //1:32768
#pragma config DSWDTOSC = INTOSCREF //DSWDT uses INTOSC/INTRC as clock
#pragma config RTCOSC = T1OSCREF    //RTCC uses T1OSC/T1CKI as clock
#pragma config DSBOREN = OFF        //Zero-Power BOR disabled in Deep Sleep
#pragma config DSWDTEN = OFF        //Disabled
#pragma config DSWDTPS = 8192       //1:8,192 (8.5 seconds)
#pragma config IOL1WAY = OFF        //IOLOCK bit can be set and cleared
#pragma config MSSP7B_EN = MSK7     //7 Bit address masking
#pragma config WPFP = PAGE_1        //Write Protect Program Flash Page 0
#pragma config WPEND = PAGE_0       //Start protection at page 0
#pragma config WPCFG = OFF          //Write/Erase last page protect Disabled
#pragma config WPDIS = OFF          //WPFP[5:0], WPEND, and WPCFG bits ignored7



#include "../Headers/PowerRGBLEDController.h"
/*
//Bootloader support code start
extern void _startup(void); // See c018i.c in your C18 compiler dir
#pragma code _RESET_INTERRUPT_VECTOR = 0x001000

void _reset(void) {
    _asm goto _startup _endasm
}
#pragma code

#define REMAPPED_RESET_VECTOR_ADDRESS		0x1000
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x1008
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS	0x1018

 */
uint16_t timeLeft = 0;
uint8_t presetState = 0;
uint8_t currentPreset = 0;
uint8_t presetOffset = 0;
uint8_t codeIR = 0;
uint8_t bitNumber = 0;
uint8_t keyToSet = 0;



uint8_t packetBuffer2[20];
uint8_t codeIRValues[30];

#pragma code low_vector=0x18

void interrupt_at_low_vector(void) {
    _asm GOTO low_isr _endasm
}
#pragma code	// Return to default code section

#pragma interruptlow low_isr

void low_isr(void) {

    if (INTCONbits.TMR0IF) {
        INTCONbits.TMR0IF = 0;
        TMR0H = 0x48;
        TMR0L = 0xE4;
        timeLeft--;

        if (timeLeft == 0) {
            switch (presetState) {
                case 0: presetState++;
                    timeLeft = DataEERead(presetOffset + TIME_OFF_EE_OFFSET)*60; // Loads preset's Off time
                    setOutputColors(4080, 4080, 4080); // Turns LED Off
                    break;

                case 1: presetState++;
                    timeLeft = DataEERead(presetOffset + SELECTION2_TIME_EE_OFFSET)*60;
                    setOutputColors(bytesToWord(DataEERead(presetOffset + SELECTION2_R_EE_OFFSET), DataEERead(presetOffset + SELECTION2_R_EE_OFFSET + 1)),
                    bytesToWord(DataEERead(presetOffset + SELECTION2_G_EE_OFFSET), DataEERead(presetOffset + SELECTION2_G_EE_OFFSET + 1)),
                    bytesToWord(DataEERead(presetOffset + SELECTION2_B_EE_OFFSET), DataEERead(presetOffset + SELECTION2_B_EE_OFFSET + 1)));
                    break;
                case 2:
                    setOutputColors(4080, 4080, 4080);
                    T0CONbits.TMR0ON = 0;

                    break;
                default: break;
            }
        }

    }
}

#pragma code high_vector=0x8

void interrupt_at_high_vector(void) {
    _asm GOTO high_isr _endasm
}
#pragma code	// Return to default code section


#pragma interrupt high_isr save=PROD	 //Context Save

void high_isr(void) {


    if (PIR1bits.CCP1IF) {
        PIR1bits.CCP1IF = 0; // Clear the interrupt flag       
        PORTBbits.RB4 = 1;
        PORTBbits.RB4 = 0;
        TMR3H = 0;
        TMR3L = 0;
    }

    if (INTCON3bits.INT1F) {
        int i;
      
        if (bitNumber < 1){
            T1CONbits.TMR1ON = 1;
            PIE1bits.TMR1IE = 0;
            PIR1bits.TMR1IF = 0;
            bitNumber++;
        }else {
            if (TMR1L > 135) //140
                codeIR++;
            codeIR = codeIR << 1;
            codeIRValues[bitNumber] = TMR1L;
            bitNumber++;
            TMR1H=0;
            TMR1L=0;
            
            INTCON3bits.INT1F = 0;
            
            if (bitNumber > 31) {

                if (keyToSet>0){
                 
                 DataEEWrite(codeIR,keyToSet);
                 sendIRCodes();
                } else if (keyToSet==0){
                    for (i=0; i<11; i++){
                        if (DataEERead(i)==codeIR)
                            initPresetCycle(i);
                    }
                    if (DataEERead(11)==codeIR)
                        //START
                        packetBuffer2[0] = codeIR;
                    else if (DataEERead(12)==codeIR)
                        //STOP
                        packetBuffer2[0] = codeIR;
                }                
                keyToSet = 0;
                INTCON3bits.INT1E = 0;
                INTCON3bits.INT1F = 0;
                PIR1bits.TMR1IF = 0;
                PIE1bits.TMR1IE = 1;

            }
        }
    }


    if (PIR1bits.TMR1IF == 1) {
        T1CONbits.TMR1ON = 0;
        PIR1bits.TMR1IF = 0;
        PIE1bits.TMR1IE = 0;
        INTCON3bits.INT1E = 1;
        bitNumber = 0;
        codeIR = 0;
        TMR1L = 0;
        TMR1H = 0;

    }
}


void initializeSystem(void);

void main(void) {

    char USB_In_Buffer[10];
    uint8_t bytesReceived;

    initializeSystem(); //Initializes the system.

    while (1) {
#if defined(USB_POLLING)

        // Check bus status and service USB interrupts.
        USBDeviceTasks(); // Interrupt or polling method.  If using polling, must call
        // this function periodically. 
#endif

        bytesReceived = getsUSBUSART(USB_In_Buffer, 10); // Gets USB recieved bytes buffer

        if (bytesReceived > 0) {
            recieveUSBPacket(USB_In_Buffer, bytesReceived); //Passes recieved data to USB_HANDLER
        }
        bytesReceived = 0;

    }
}

void initIR(void) {

    //Config INT0 Interrupt for Pin RB0

    TRISBbits.TRISB6 = 0; // Config RC0 as output

    iPPSInput(IN_FN_PPS_INT1, IN_PIN_PPS_RP12); //Config INT1 signal from RC0

    INTCON3bits.INT1F = 0; // Clear INT1 interrupt flag
    INTCON3bits.INT1E = 1; // Enable INT1 interrupt
    INTCON2bits.INTEDG1 = 1; // Sets INT1 interrupt on Rising edge (This means rising edge for protocol sin IR recieve inverts the signal)
    INTCON3bits.INT1IP = 1; // Sets INT1 high priority interrupt


    //Config Timer 1 for IR Decoding

    T1CON = 0b00111010; // Timer 1 Off FOSC/4, Prescaler 1, 16 Bit
    //TMR1H =0xF5;
    //TMR1L = 0x94;         //65535 - 2667 = 62868  1778uS
    TMR1H = 0x0B;
    TMR1L = 0x1B; //65535 - 2667 = 62868  1778uS
    PIR1bits.TMR1IF = 0; // Clear Timer 1 Interrupt flag.
    // PIE1bits.TMR1IE = 1; // Enable Timer 1 Interrupt.
    IPR1bits.TMR1IP = 1; // Sets High priority for Timer 1
    T1CONbits.TMR1ON = 0;
}

void initializeSystem(void) {

    unsigned int pll_startup_counter;


    OSCCON = 0x60; //Oscillator config.
    OSCTUNEbits.PLLEN = 1; //Enable the PLL and wait 2+ms until the PLL locks before enabling USB module
    pll_startup_counter = 600;
    while (pll_startup_counter--);

    ANCON0 = 0xFF; // Configures all pins as digital
    ANCON1 = 0xFF; // Configures all pins as digital

    initializeUSB();


    TRISCbits.TRISC1 = 1;

    //PORTCbits.RC1 = 1;

    TRISB = 0b11000000; // Sets tristates config for PORTB
    TRISCbits.TRISC7 = 0; // Sets RC7 as Output
    TRISCbits.TRISC2 = 1; // Sets RC2 as Input

    iPPSInput(IN_FN_PPS_T3CK, IN_PIN_PPS_RP13); //Configures RP13 to input T3CK signal

    /*Config Timer 3 and CCP1*/

    T3CON = 0b10000011; //External Source, Prescaler 0, 16bit, timer ON

    TCLKCONbits.T3CCP1 = 0; //ECCP1 and ECCP2 both use Timer3 (COMPARE) and Timer4 for (PWM)
    TCLKCONbits.T3CCP2 = 1;

    CCP1CON = 0b00001010; // Sets the ECCP to work as Capture
    CCPR1 = 4080; // Value to be compared

    PIE1bits.CCP1IE = 1; // Enable interrupt for CCP1
    PIR1bits.CCP1IF = 0; // Clear interrupt flag for CCP1
    IPR1bits.CCP1IP = 1; // Sets High priority for CCP1
    RCONbits.IPEN = 1; // Enables interrupts priorities



    iPPSOutput(OUT_PIN_PPS_RP3, OUT_FN_PPS_CCP2P2A); //Configures PPS to output CCP2 through RP3
    PR4 = 10; // PWM Period
    T4CON = 0b00000100; // 0 Postcaler and Prescaler, Timer ON

    //CCPR2L = 0b00000001; // PWM Duty Cycle
    CCPR2L = 5; // PWM Duty Cycle
    CCP2CON = 0b00011100; // Configures CCP2 for PWM operation

    // Config Timer 0 for time

    T0CON = 0b00000110; //Timer 0 Off / 16bits / Int OSC / Preescaler 4
    TMR0L = 0xE4; // 65535-18660 = 46875   18660 = 0x48 | 0xE4
    TMR0H = 0x48; // 46875*(1/(24/4)Mhz)*128 Preescaler = 1 s // Exact one second delay

    INTCONbits.TMR0IF = 0; // Clear Timer 0 Interrupt flag.
    INTCONbits.TMR0IE = 1; // Enable Timer 0 Interrupt.
    INTCON2bits.TMR0IP = 0; // Set Timer 0 Low Priority Interrupt for



    initIR();

    TLC594X_Init(); // Initializes the TLC5946

    DataEEInit(); // Initializes EEPROM Emulation

    TLC594X_LoadDotCorrectionValues();
    TLC594X_LoadGrayScaleValues();



     T0CONbits.TMR0ON = 1;       // Start Timer 0;
    INTCONbits.GIE = 1; // Enables global interrupts
    INTCONbits.PEIE = 1; // Enables peripheral interrupts

   // startPattern();


}

void startPattern(void){
    uint16_t x,i;
    uint16_t time=40000;

    setOutputColors(0,4080,4080);
    for (i=0; i<2 ; i++)
    for (x=0; x<time ; x++);
    setOutputColors(4080,0,4080);
    for (i=0; i<2 ; i++)
    for (x=0; x<time ; x++);
    setOutputColors(4080,4080,0);
    for (i=0; i<2 ; i++)
    for (x=0; x<time ; x++);
    setOutputColors(2000,0,2000);
    for (i=0; i<2 ; i++)
    for (x=0; x<time ; x++);
    setOutputColors(2000,2000,0);
    for (i=0; i<2 ; i++)
    for (x=0; x<time ; x++);
    setOutputColors(0,2000,2000);
    for (i=0; i<2 ; i++)
    for (x=0; x<time ; x++);
    setOutputColors(4080,4080,4080);  
}

void setIRKey(uint8_t _keyToSet) {
    keyToSet = _keyToSet;
}

void initPresetCycle(uint8_t presetNumber) {
    uint16_t red,green,blue;
    currentPreset = presetNumber-1;
    presetOffset = PRESETS_EE_OFFSET*currentPreset;

    TMR0H = 0x48; // Load Timer to generate 1 second
    TMR0L = 0xE4;

    timeLeft = DataEERead(presetOffset + SELECTION1_TIME_EE_OFFSET)*60;

    setOutputColors(bytesToWord(DataEERead(presetOffset + SELECTION1_R_EE_OFFSET), DataEERead(presetOffset + SELECTION1_R_EE_OFFSET + 1)),
            bytesToWord(DataEERead(presetOffset + SELECTION1_G_EE_OFFSET), DataEERead(presetOffset + SELECTION1_G_EE_OFFSET + 1)),
            bytesToWord(DataEERead(presetOffset + SELECTION1_B_EE_OFFSET), DataEERead(presetOffset + SELECTION1_B_EE_OFFSET + 1)));

    presetState = 0; // Reset Preset State
    INTCONbits.TMR0IF = 0; // Clear Timer 0 Interrupt flag.
    INTCONbits.TMR0IE = 1; // Enable Timer 0 Interrupt.
    INTCON2bits.TMR0IP = 0; // Set Timer 0 Low Priority Interrupt for
    T0CONbits.TMR0ON = 1; // Start Timer 0;

}

void setOutputColors(uint16_t R, uint16_t G, uint16_t B) {
    TLC594X_SetGrayScaleValue(1, R);
    TLC594X_SetGrayScaleValue(2, G);
    TLC594X_SetGrayScaleValue(3, B);
    TLC594X_LoadGrayScaleValues();
}